/*
 * Improved from chapter4
 */

package helloscala.practise.chapter6

trait AbstractSubject {
  type Observer

  private var observers = List[Observer]()
  def addObserver(observer: Observer) = observers ::= observer
  def notifyAllObservers = {observers foreach notify _}
  def notify(observer: Observer)
}

/**
 * works exactly like chapter4 direct Subject
 */
trait Subject4ReceiveUpdate extends AbstractSubject {
  type Observer = {def receiveUpdate(subject: Any)}

  def notify(observer: Observer) = observer.receiveUpdate(this)
}

/**
 * more advanced abstraction, don't even hardcode "receiveUpdate()"
 * such thing in a concrete Subject, where it all depends on specific observer.
 *
 * Reason: 1. observer is usually usecase specific
 *         2. trait of operating observer is usually common in logic
 */
trait Subject4Functional extends AbstractSubject {
  type Observer = (AbstractSubject) => Unit //higher abstraction than "receiveUpdate(subject)"

  def notify(observer: Observer) = observer(this)
}

abstract class Widget
trait Clickable {
  def click
}

trait ObservableClicks extends Clickable with AbstractSubject {
  abstract override def click = {
    super.click
    super.notifyAllObservers
  }
}

class ButtonWithCallback extends Widget with Clickable {
  def click = {
    //some process in here
  }
}

class SelectiveCounter {
  var count = 0

  def receiveUpdate(subject: Any) = {
    count += 1
  }
}


